package plp.prolog.memory;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map.Entry;

import plp.prolog.declaration.Termo;
import plp.prolog.declaration.Termo.Tipo;
import plp.prolog.declaration.Variavel;

import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util;

public class Contexto implements Cloneable{

	private HashMap<String, Termo> mapementoUnificacao;
	private HashMap<Variavel, ArrayList<Variavel>> mapeamentoAtualizarVariavel;
	private HashMap<String, Termo> impressaoUnificacao;

	public Contexto() {
		this.mapementoUnificacao = new HashMap<String, Termo>();
		this.mapeamentoAtualizarVariavel = new HashMap<Variavel, ArrayList<Variavel>>();
	}
	
	public Contexto(Contexto contexto) {
		this.mapementoUnificacao = contexto.getMapementoUnificacao();
	}
	
	public boolean checarUnificacao(String key){
		return mapementoUnificacao.containsKey(key);
	}
	
	public Termo getValorTermo(String key){
		return mapementoUnificacao.get(key);
	}
	
	public void unificar(String key, Termo termo){
		if(termo.getTipo() == Tipo.VARIAVEL){
			Variavel variavel = (Variavel) termo;
			atualizarVariavel(variavel);
		}
		this.mapementoUnificacao.put(key, termo);
		
	}

	public void printUnificacoes(){
		for(Entry<String, Termo> entry : mapementoUnificacao.entrySet() ){
			Util.println( entry.getKey() + " = " + entry.getValue().toString());
		}
	}
	
	private void atualizarVariavel(Variavel variavel){
		ArrayList<Variavel> variaveisParaAtualizar = mapeamentoAtualizarVariavel.remove(variavel);
		
		if(variaveisParaAtualizar != null){
			for(Variavel v : variaveisParaAtualizar){
				v.setValor(variavel.getValor());
				atualizarVariavel(v);
			}
		}
	}
	
	public void criarReferenciaEntreVariaveis(Variavel variavelReferenciada, Variavel variavel){
		ArrayList<Variavel> variaveisParaAtualizar = mapeamentoAtualizarVariavel.get(variavelReferenciada);
		
		if(variaveisParaAtualizar == null){
			variaveisParaAtualizar = new ArrayList<Variavel>();
			mapeamentoAtualizarVariavel.put(variavelReferenciada, variaveisParaAtualizar);
		}
		
		variaveisParaAtualizar.add(variavel);
	}
	
	public HashMap<String, Termo> getMapementoUnificacao() {
		return mapementoUnificacao;
	}

	public Object clone() throws CloneNotSupportedException{
		return super.clone();
	}
}
